package com.mentorgen.tools.profile.runtime;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.mentorgen.tools.profile.Controller;

public class BundleInternals {

	private String _loaderID;
	private String _bundleSymbolicName;
	private String _exportPackage;
	private String _includeResource;
	private String _privatePackage;
	private String _importPackage;
	private String _conditionalPackage;
	private String _bundleName;
	private String _bundleManifestVersion;
	private String _bundleVersion;
	private String _serviceComponent;
	private String _bundleDescription;
	private String _bundleLicense;
	private String _bundleVendor;

	public static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName";
	public static final String BUNDLE_NAME = "Bundle-Name";
	public static final String BUNDLE_VERSION = "Bundle-Version";
	public static final String IMPORT_PACKAGE ="Import-Package";
	public static final String EXPORT_PACKAGE ="Export-Package";
	public static final String BUNDLE_DESCRIPTION ="Bundle-Description";
	public static final String BUNDLE_LICENSE ="Bundle-License";
	public static final String BUNDLE_VENDOR ="Bundle-Vendor";
	public static final String INCLUDE_RESOURCE ="Include-Resource";
	public static final String PRIVATE_PACKAGE ="Private-Package";
	public static final String CONDITIONAL_PACKAGE ="Conditional-Package";
	public static final String BUNDLE_MANIFEST_VERSION ="Bundle-ManifestVersion";
	public static final String SERVICE_COMPONENT ="Service-Component";
	
	private List<ServiceInternals> _services;

	private BundleInternals(String loaderID){
		_loaderID = loaderID;
		_services  = new ArrayList<ServiceInternals>();
	}

	public String getLoaderID(){
		return _loaderID;
	}

	public String getBundleSymbolicName(){
		return _bundleSymbolicName;
	}
	
	public void addServiec(ServiceInternals service){
		_services.add(service);
	}
	
	public ServiceInternals getService(String serviceClass){
		for (ServiceInternals service : _services)
			if (service.getServiceClass().equals(serviceClass))
				return service;
		return null;
	}

	public final static BundleInternals getBundleInfo(ClassLoader loader){

		BundleInternals bundle = new BundleInternals(Integer.toString(loader.hashCode()));

		try {

			java.io.InputStream manifestStream = loader.getResourceAsStream("META-INF/MANIFEST.MF");
			java.util.jar.Manifest manifest = new java.util.jar.Manifest(manifestStream);

			java.util.jar.Attributes attributes = manifest.getMainAttributes();
			bundle._bundleSymbolicName = attributes.getValue(BundleInternals.BUNDLE_SYMBOLIC_NAME);
			bundle._bundleName = attributes.getValue(BundleInternals.BUNDLE_NAME);
			bundle._bundleVersion = attributes.getValue(BundleInternals.BUNDLE_VERSION);
			bundle._importPackage = attributes.getValue(BundleInternals.IMPORT_PACKAGE);
			bundle._exportPackage = attributes.getValue(BundleInternals.EXPORT_PACKAGE);
			bundle._bundleDescription = attributes.getValue(BundleInternals.BUNDLE_DESCRIPTION);
			bundle._bundleLicense = attributes.getValue(BundleInternals.BUNDLE_LICENSE);
			bundle._bundleVendor = attributes.getValue(BundleInternals.BUNDLE_VENDOR);
			bundle._includeResource = attributes.getValue(BundleInternals.INCLUDE_RESOURCE);
			bundle._privatePackage = attributes.getValue(BundleInternals.PRIVATE_PACKAGE);
			bundle._conditionalPackage = attributes.getValue(BundleInternals.CONDITIONAL_PACKAGE);
			bundle._bundleManifestVersion = attributes.getValue(BundleInternals.BUNDLE_MANIFEST_VERSION);
			bundle._serviceComponent = attributes.getValue(BundleInternals.SERVICE_COMPONENT);

		} catch (Exception e) {
			if (Controller._debug){
				System.err.println("Manufest Load Error");
			}
		}

		return bundle;
	}

	public final void writeXML(PrintWriter writer, int depth){

		for (int i = 0; i < depth; i++)
			writer.print("\t");

		writer.println("<bundle id=\"" + _loaderID + "\" sn=\"" + _bundleSymbolicName +"\">");
		writeElem(BundleInternals.BUNDLE_SYMBOLIC_NAME, _bundleSymbolicName, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_NAME, _bundleName, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_VERSION, _bundleVersion, writer, depth + 1);
		writeElem(BundleInternals.IMPORT_PACKAGE, _importPackage, writer, depth + 1);
		writeElem(BundleInternals.EXPORT_PACKAGE, _exportPackage, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_DESCRIPTION, _bundleDescription, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_LICENSE, _bundleLicense, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_VENDOR, _bundleVendor, writer, depth + 1);
		writeElem(BundleInternals.INCLUDE_RESOURCE, _includeResource, writer, depth + 1);
		writeElem(BundleInternals.PRIVATE_PACKAGE, _privatePackage, writer, depth + 1);
		writeElem(BundleInternals.CONDITIONAL_PACKAGE, _conditionalPackage, writer, depth + 1);
		writeElem(BundleInternals.BUNDLE_MANIFEST_VERSION, _bundleManifestVersion, writer, depth + 1);
		writeElem(BundleInternals.SERVICE_COMPONENT, _serviceComponent, writer, depth + 1);
		
		for (int i = 0; i < _services.size(); i++){
			writeService(_services.get(i), writer, depth + 2);
		}

		for (int i = 0; i < depth; i++)
			writer.print("\t");
		writer.println("</bundle>");

	}
	
	private static final void writeService(ServiceInternals service, PrintWriter writer, int depth){
		
		try{
			

			for (int i = 0; i < depth; i++)
				writer.print("\t");
			
			writer.print("<service"); 
			attribute(writer, "c", service.getServiceClass());
			attribute(writer, "id", service.getServiceID());
			attribute(writer, "in", service.getInData());
			attribute(writer, "out", service.getOutData());
			attribute(writer, "ttl", service.getTotalData());
			writer.println("/>");
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	private static final void writeElem(String name, String value, PrintWriter writer, int depth){

		if (value == null)
			return;

		for (int i = 0; i < depth; i++)
			writer.print("\t");

		writer.print(xmlElemOpenClose(name.toLowerCase(), 1, true));

		char[] string = value.toString().toCharArray();

		for (char c : string) {
			if (c == '<') {
				writer.print("&lt;");
			} else if (c == '>') {
				writer.print("&gt;");
			} else {
				writer.print(c);
			}
		}
		writer.println(xmlElemOpenClose(name.toLowerCase(), 1, false));
	}

	private static final String xmlElemOpenClose(String elemName, int depth, boolean open){
		StringBuffer depthStr = new StringBuffer("");

		if (open)
			for (int i = 0; i < depth; i++)
				depthStr.append("\t");

		return (open ? depthStr.append("<" + elemName + ">").toString() :
			depthStr.append("</" + elemName + ">").toString());
	}
	
	private static void attribute(PrintWriter writer, String name,
			Object value) throws IOException {
		writer.print(" ");
		writer.print(name);
		writer.print("=\"");

		char[] string = value.toString().toCharArray();

		for (char c : string) {
			if (c == '<') {
				writer.print("&lt;");
			} else if (c == '>') {
				writer.print("&gt;");
			} else {
				writer.print(c);
			}
		}

		writer.print("\"");
	}

}
